/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, Hardware
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef FOUNDATION_GRAPHIC_3D_STANDARD_RENDER_SERVICE_ENGINE_SERVICE_H_
#define FOUNDATION_GRAPHIC_3D_STANDARD_RENDER_SERVICE_ENGINE_SERVICE_H_

#include <shared_mutex>
#include <future>
#include <queue>
#include <functional>
#include <thread>

#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl31.h>
#include <GLES2/gl2ext.h>

#include "i_engine.h"
#include "scene_view_core.h"

namespace OHOS {
namespace Render3D {
using SceneViewCore = OHOS::Render3D::SceneViewCore;

class EngineService {
public:
    using EngineTask = void();
    class Message {
    public:
        explicit Message(const std::function<EngineTask>& task);
        Message(Message&& msg);
        Message& operator=(Message&& msg);
        ~Message() = default;

        std::function<EngineTask> task_;
        std::promise<void> pms_;
        std::future<void> ftr_ = pms_.get_future();

        void Execute();
        void Finish();
    private:
        friend EngineService;
        std::shared_future<void> GetFuture();
    };

    static EngineService& GetInstance();
    void Register(int32_t key, EGLContext context);
    void Unregister(int32_t key);
    void PushSyncMessage(const std::function<EngineTask>& task);
    std::shared_future<void> PushAsyncMessage(const std::function<EngineTask>& task);
private:
    EngineService(const EngineService&) = delete;
    EngineService operator=(const EngineService&) = delete;
    EngineService() = default;
    ~EngineService();

    void Start();
    void Stop();
    void InitEngine();
    void DeInitEngine();
    void EngineThread();
    void SetName();

    EGLContext eglContext_ = EGL_NO_CONTEXT;

    std::queue<Message> messageQueue_;
    std::condition_variable messageQueueCnd_;
    std::mutex messageQueueMut_;

    std::thread loop_;
    std::atomic_int registerViewCount_ { 0 };
    bool exit_ = false;
};
} // namespace OHOS
} // namespace Render3D
#endif